package generator.util.input_interpreter;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import generator.datastructure.MethodDeclaration;
import generator.util.DocTransformer;

/**Esta clase se encarga de proveer la declaración de los métodos que el usuario desea paralelizar,
 * así como también el nombre de la clase que contiene dichos métodos y su ubicación en la estructura
 * de directorios.
 * Todos estos datos son obtenidos a partir de un archivo xml. Un ejemplo del mismo puede encontrase
 * en el directorio config del proyecto con el nombre App-config.xml
 * @author Hirsch-Fernández
 * */
public class XMLParallelizerInterpreter implements ParallelizerInterpreter{

	/**Ruta completa del archivo que sirve de entrada para el intérprete*/
	private String xmlConfig = "config"+System.getProperty("file.separator")+"App-config.xml";
	
	/**Objeto utilizado para evaluar expresiones xpath sobre archivos xml*/
	private XPath xpath = null;
	
	/**Documento que representa el archivo xml bajo la forma de árbol DOM*/
	private Document input = null;	
	
	/**constructor vacío de la clase*/
	public XMLParallelizerInterpreter(){		
		xpath = XPathFactory.newInstance().newXPath();		
		input = DocTransformer.xmlToDom(new File(xmlConfig));
	}
	
		
	/**@param xmlConfig
	 * el archivo de configuración del cual el intérprete obtendrá los datos tales como la clase que
	 * contiene los métodos a gridificar, el directorio donde se halla contenida y las declaraciones de 
	 * los métodos a gridificar propiamente dichos.*/
	public void setXmlConfig(String xmlConfig) {
		this.xmlConfig = xmlConfig;
		input = DocTransformer.xmlToDom(new File(xmlConfig));
	}


	/**@return el archivo de configuración del cual el intérprete obtiene los datos tales como la clase que
	 * contiene los métodos a gridificar, el directorio donde se halla contenida y las declaraciones de 
	 * los métodos a gridificar propiamente dichos.*/
	public String getXmlConfig() {
		return xmlConfig;
	}
	
	/**{@inheritDoc}*/
	@Override
	public List<MethodDeclaration> getMethodsToParallelize() {
					
		
		ArrayList<MethodDeclaration> retorno = new ArrayList<MethodDeclaration>(); 
		try {
			String classToGridify = (String)xpath.evaluate("//component[@id='classToGridify']/@name", input, XPathConstants.STRING);			
			NodeList methods = (NodeList)xpath.evaluate("//component[@id='classToGridify']/method", input, XPathConstants.NODESET);
			
			for (int i = 0; i < methods.getLength(); i++){
				String methodName = ((Element)methods.item(i)).getAttribute("name");
				String returnType = ((Element)methods.item(i)).getAttribute("type");
				ArrayList<String> types = new ArrayList<String>();
				NodeList paramTypes = (NodeList)xpath.evaluate("//component[@id='classToGridify']/method/parameter", input, XPathConstants.NODESET);
				for (int j = 0; j < paramTypes.getLength(); j++){
					types.add(((Element)paramTypes.item(j)).getAttribute("type"));
				}
				retorno.add(new MethodDeclaration(classToGridify,returnType,methodName,types));				 
			}			
		} catch (XPathExpressionException e) {
			System.err.println("Error al leer el archivo de declaración de métodos paralelizables, compruebe que el mismo respete la estrucutura");			
			return retorno;
		}				
		return retorno;
	}
	
	
	/**{@inheritDoc}*/
	@Override
	public String getClassToParallelize() {
		try {
			String className = (String)xpath.evaluate("//component[@id='classToGridify']/@name", input, XPathConstants.STRING);
			int begin = className.lastIndexOf(".");
			if (begin > 0)
				className = className.substring(begin+1, className.length());
			return this.getClassToParallelizeContentDirectory()+className+".java";
		} catch (XPathExpressionException e) {
			System.err.println("Error al intentar obtener el nombre de la clase a paralelizar");
			e.printStackTrace();
			return "";
		}		
	}
	
	/**{@inheritDoc}*/
	@Override
	public String getClassToParallelizeContentDirectory() {
		
		try {
			return (String)xpath.evaluate("//component[@id='classToGridify']/@location", input, XPathConstants.STRING);
		} catch (XPathExpressionException e) {
			System.err.println("Error al intentar obtener el directorio que contiene la clase a paralelizar");
			e.printStackTrace();
			return "";
		}
	}

}
